package cc.cary.warehouse.untils;

import cc.cary.warehouse.untils.mapper.IDMapper;
import cc.cary.warehouse.untils.mapper.KeyMapper;
import cc.cary.warehouse.untils.mapper.Mapper;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 集合处理 辅助类
 *
 * @author Cary
 * @date 2023/1/16
 */
public class Streams {

    /**
     * 目标列表是否为空
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> boolean isEmpty(List<T> list) {
        return list == null || list.isEmpty();
    }


    /**
     * 目标列表是否不为空
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> boolean isNotEmpty(List<T> list) {
        return !Streams.isEmpty(list);
    }

    /**
     * 返回非空列表
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<T> listNotNull(List<T> list) {
        return Streams.isEmpty(list) ? Collections.emptyList() : list;
    }

    /**
     * 列表第一个对象
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> Optional<T> first(List<T> list) {
        return Optional.ofNullable(Streams.isNotEmpty(list) ? list.get(0) : null);
    }

    /**
     * 列表最后一个对象
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> Optional<T> last(List<T> list) {
        return Optional.ofNullable(Streams.isNotEmpty(list) ? list.get(list.size() - 1) : null);
    }

    /**
     * 映射到另外一个列表
     *
     * @param list
     * @param func
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> map(List<T> list, Function<T, R> func) {
        return list.stream().map(func).collect(Collectors.toList());
    }

    /**
     * 过滤列表
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 映射到另外一个列表, 并过滤列表
     *
     * @param list
     * @param func
     * @param predicate
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> mapAndFilter(List<T> list, Function<T, R> func, Predicate<R> predicate) {
        return list.stream().map(func).filter(predicate).collect(Collectors.toList());
    }

    /**
     * 过滤列表, 并映射到另外一个列表
     *
     * @param list
     * @param predicate
     * @param func
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> filterAndMap(List<T> list, Predicate<T> predicate, Function<T, R> func) {
        return list.stream().filter(predicate).map(func).collect(Collectors.toList());
    }

    /**
     * 列表按keyFunc返回的key转换成map
     *
     * @param list
     * @param keyFunc
     * @param <T>
     * @return
     */
    public static <K, V> Map<K, V> toMapByKey(List<V> list, Function<V, K> keyFunc) {
        Map<K, V> maps = new HashMap<>(list.size());
        list.forEach(v -> {
            K key = keyFunc.apply(v);
            maps.put(key, v);
        });
        return maps;
    }

    /**
     * 转换成按key的分组
     *
     * @param list
     * @param keyFunc
     * @param <T>
     * @return
     */
    public static <K, V> Map<K, List<V>> groupByKey(List<V> list, Function<V, K> keyFunc) {
        return list.stream().collect(Collectors.groupingBy(keyFunc));
    }

    /**
     * String数组转成Integer列表
     *
     * @param array
     * @return
     */
    public static List<Integer> arrayIdsToIntegerList(String[] array) {
        return Stream.of(array)
                .filter(v -> !StringUtils.hasLength(v))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
    }

    /**
     * String数组转成Long列表
     *
     * @param array
     * @return
     */
    public static List<Long> arrayIdsToLongList(String[] array) {
        return Stream.of(array)
                .filter(v -> !StringUtils.hasLength(v))
                .map(Long::parseLong)
                .collect(Collectors.toList());
    }

    /**
     * 对目标列表所有的子元素转换成Long格式
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<Long> toLongList(List<T> list) {
        return list.stream().map(v -> Long.parseLong(String.valueOf(v))).collect(Collectors.toList());
    }

    /**
     * 对目标列表所有的子元素转换成Double格式
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<Double> toDoubleList(List<T> list) {
        return list.stream().map(v -> Double.parseDouble(String.valueOf(v))).collect(Collectors.toList());
    }

    /**
     * 对目标列表所有的子元素转换成String格式
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<String> toStrList(List<T> list) {
        return list.stream().map(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 对目标列表所有的子元素转换成JSON格式
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<String> toJsonList(List<T> list) {
        return list.stream().map(Beans::json).collect(Collectors.toList());
    }

    /**
     * 对目标列表所有的子元素转换成指定Class格式
     *
     * @param list
     * @param clz
     * @param <R>
     * @return
     */
    public static <R> List<R> toObjectList(List<String> list, Class<R> clz) {
        return list.stream().map(v -> Beans.beans(v, clz)).collect(Collectors.toList());
    }

    /**
     * 按predicate条件判断数组中是否存在符合条件的成员
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return 若任一成员符合条件，返回true, 否则返回false
     */
    public static <T> boolean anyMatch(List<T> list, Predicate<T> predicate) {
        return list.stream().anyMatch(predicate);
    }

    /**
     * 按predicate条件判断数组中是否存在符合条件的成员
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return 若所有成员符合条件，返回true, 否则返回false
     */
    public static <T> boolean allMatch(List<T> list, Predicate<T> predicate) {
        return list.stream().allMatch(predicate);
    }

    /**
     * 数组浅拷贝
     *
     * @param list
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> clone(List<T> list) {
        List<Object> dest = new ArrayList<>(Arrays.asList(new Object[list.size()]));
        Collections.copy(dest, list);
        return (List<T>) dest;
    }

    /**
     * list逆序
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<T> reverse(List<T> list) {
        List<T> dest = Streams.clone(list);
        Collections.reverse(dest);
        return dest;
    }

    /**
     * 按predicate条件在数组中查找第一个符合条件的成员
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return 找到的成员，没找到即为Optional.empty()
     */
    public static <T> Optional<T> find(List<T> list, Predicate<T> predicate) {
        for (T l : list) {
            if (predicate.test(l)) {
                return Optional.of(l);
            }
        }

        return Optional.empty();
    }

    /**
     * 按predicate条件在数组中从后往前查找第一个符合条件的成员
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return 找到的成员，没找到即为Optional.empty()
     */
    public static <T> Optional<T> findLast(List<T> list, Predicate<T> predicate) {
        List<T> listReverse = Streams.reverse(list);
        for (T l : listReverse) {
            if (predicate.test(l)) {
                return Optional.of(l);
            }
        }

        return Optional.empty();
    }

    /**
     * 计算列表指定成员的最大值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalInt maxIntBy(List<T> list, ToIntFunction<? super T> func) {
        return list.stream().mapToInt(func).max();
    }

    /**
     * 计算列表指定成员的最大值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalDouble maxDoubleBy(List<T> list, ToDoubleFunction<? super T> func) {
        return list.stream().mapToDouble(func).max();
    }

    /**
     * 计算列表指定成员的最大值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalLong maxLongBy(List<T> list, ToLongFunction<? super T> func) {
        return list.stream().mapToLong(func).max();
    }


    /**
     * 计算列表指定成员的最小值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalInt minIntBy(List<T> list, ToIntFunction<? super T> func) {
        return list.stream().mapToInt(func).min();
    }

    /**
     * 计算列表指定成员的最小值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalDouble minDoubleBy(List<T> list, ToDoubleFunction<? super T> func) {
        return list.stream().mapToDouble(func).min();
    }

    /**
     * 计算列表指定成员的最小值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalLong minLongBy(List<T> list, ToLongFunction<? super T> func) {
        return list.stream().mapToLong(func).min();
    }


    /**
     * 计算列表指定成员的平均值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalDouble avgIntBy(List<T> list, ToIntFunction<? super T> func) {
        return list.stream().mapToInt(func).average();
    }

    /**
     * 计算列表指定成员的平均值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalDouble avgDoubleBy(List<T> list, ToDoubleFunction<? super T> func) {
        return list.stream().mapToDouble(func).average();
    }

    /**
     * 计算列表指定成员的平均值
     *
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> OptionalDouble avgLongBy(List<T> list, ToLongFunction<? super T> func) {
        return list.stream().mapToLong(func).average();
    }

    /**
     * 连接列表指定成员
     *
     * @param list
     * @param func
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> String join(List<T> list, Function<T, R> func) {
        List<String> joinLists = list.stream().map(v -> String.valueOf(func.apply(v))).collect(Collectors.toList());
        return String.join(",", joinLists);
    }

    /**
     * 连接列表指定成员
     *
     * @param list
     * @param func
     * @param delimiter
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> String joinByDelimiter(List<T> list, Function<T, R> func, String delimiter) {
        List<String> joinLists = list.stream().map(v -> String.valueOf(func.apply(v))).collect(Collectors.toList());
        return String.join(delimiter, joinLists);
    }

    /**
     * 对列表指定的所有子元素值返回一个新列表
     *
     * @param lists
     * @param func
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> List<V> elements(List<K> lists, Function<K, V> func) {
        return lists.stream().map(func).collect(Collectors.toList());
    }

    /**
     * 简单类型交集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> simpleIntersection(List<T> list1, List<T> list2) {
        List<T> res = clone(list1);
        res.retainAll(list2);
        return res;
    }

    /**
     * 简单类型无重并集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> simpleUnion(List<T> list1, List<T> list2) {
        List<T> tList1 = clone(list1);
        List<T> tList2 = clone(list2);
        tList2.removeAll(tList1);
        tList1.addAll(tList2);
        return tList1;
    }

    /**
     * 简单类型有重并集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> simpleOverlapUnion(List<T> list1, List<T> list2) {
        List<T> res = clone(list1);
        res.addAll(list2);
        return res;
    }

    /**
     * 简单类型差值，res = left - right
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> simpleDifferenceSetLeft(List<T> list1, List<T> list2) {
        List<T> res = clone(list1);
        res.removeAll(list2);
        return res;
    }

    /**
     * 简单类型差值，res = right - left
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> simpleDifferenceSetRight(List<T> list1, List<T> list2) {
        List<T> res = clone(list2);
        res.removeAll(list1);
        return res;
    }


    /**
     * 按两个列表id的并集返回一个新列表，如重复过滤后面的list
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> unionIdAll(List<T> list1, List<T> list2) {
        Set<IDMapper<T>> idMappersAll = new HashSet<IDMapper<T>>() {{
            addAll(new HashSet<>(Mapper.idMappers(list1)));
            addAll(new HashSet<>(Mapper.idMappers(list2)));
        }};

        return idMappersAll.stream().map(v -> v.obj).collect(Collectors.toList());
    }

    /**
     * 按两个列表key的交集返回一个新列表，过滤后面的list
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> unionId(List<T> list1, List<T> list2) {
        Triple<Set<IDMapper<T>>, Set<IDMapper<T>>, Set<IDMapper<T>>> idMapper = Streams.leftRightAllIdMapper(list1, list2);
        return idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }

    /**
     * 按两个列表id的仅在列表1中，不在列表2中,返回一个新列表
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> unionIdLeft(List<T> list1, List<T> list2) {
        Triple<Set<IDMapper<T>>, Set<IDMapper<T>>, Set<IDMapper<T>>> idMapper = Streams.leftRightAllIdMapper(list1, list2);
        return idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && !idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }


    /**
     * 按两个列表id的仅在列表2中，不在列表1中,返回一个新列表
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> unionIdRight(List<T> list1, List<T> list2) {
        Triple<Set<IDMapper<T>>, Set<IDMapper<T>>, Set<IDMapper<T>>> idMapper = Streams.leftRightAllIdMapper(list1, list2);
        return idMapper.getThird().stream().filter(v -> !idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }

    /**
     * 按两个列表key的并集返回一个新列表
     *
     * @param list1
     * @param list2
     * @param key
     * @param <T>
     * @return
     */
    public static <T> List<T> unionKeyAll(List<T> list1, List<T> list2, String... key) {
        Set<KeyMapper<T>> keyMappersAll = new HashSet<KeyMapper<T>>() {{
            addAll(new HashSet<>(Mapper.keyMappers(list1, key)));
            addAll(new HashSet<>(Mapper.keyMappers(list2, key)));
        }};

        return keyMappersAll.stream().map(v -> v.obj).collect(Collectors.toList());
    }


    /**
     * 按两个列表key的交集返回一个新列表
     *
     * @param list1
     * @param list2
     * @param key
     * @param <T>
     * @return
     */
    public static <T> List<T> unionKey(List<T> list1, List<T> list2, String... key) {
        Triple<Set<KeyMapper<T>>, Set<KeyMapper<T>>, Set<KeyMapper<T>>> idMapper = Streams.leftRightAllKeyMapper(list1, list2, key);
        return idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }

    /**
     * 按两个列表key的仅在列表1中，不在列表2中,返回一个新列表
     *
     * @param list1
     * @param list2
     * @param key
     * @param <T>
     * @return
     */
    public static <T> List<T> unionKeyLeft(List<T> list1, List<T> list2, String... key) {
        Triple<Set<KeyMapper<T>>, Set<KeyMapper<T>>, Set<KeyMapper<T>>> idMapper = Streams.leftRightAllKeyMapper(list1, list2, key);
        return idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && !idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }


    /**
     * 按两个列表key的仅在列表2中，不在列表1中,返回一个新列表
     *
     * @param list1
     * @param list2
     * @param key
     * @param <T>
     * @return
     */
    public static <T> List<T> unionKeyRight(List<T> list1, List<T> list2, String... key) {
        Triple<Set<KeyMapper<T>>, Set<KeyMapper<T>>, Set<KeyMapper<T>>> idMapper = Streams.leftRightAllKeyMapper(list1, list2, key);
        return idMapper.getThird().stream().filter(v -> !idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
    }


    private static <T> Triple<Set<IDMapper<T>>, Set<IDMapper<T>>, Set<IDMapper<T>>> leftRightAllIdMapper(List<T> list1, List<T> list2) {
        Set<IDMapper<T>> idMappers1 = new HashSet<>(Mapper.idMappers(list1));
        Set<IDMapper<T>> idMappers2 = new HashSet<>(Mapper.idMappers(list2));
        Set<IDMapper<T>> idMappersAll = new HashSet<IDMapper<T>>() {{
            addAll(new HashSet<>(Mapper.idMappers(list1)));
            addAll(new HashSet<>(Mapper.idMappers(list2)));
        }};
        return new Triple<>(idMappers1, idMappers2, idMappersAll);
    }

    private static <T> Triple<Set<KeyMapper<T>>, Set<KeyMapper<T>>, Set<KeyMapper<T>>> leftRightAllKeyMapper(List<T> list1, List<T> list2, String... key) {
        Set<KeyMapper<T>> keyMappers1 = new HashSet<>(Mapper.keyMappers(list1, key));
        Set<KeyMapper<T>> keyMappers2 = new HashSet<>(Mapper.keyMappers(list2, key));
        Set<KeyMapper<T>> keyMappersAll = new HashSet<KeyMapper<T>>() {{
            addAll(new HashSet<>(Mapper.keyMappers(list1, key)));
            addAll(new HashSet<>(Mapper.keyMappers(list2, key)));
        }};
        return new Triple<>(keyMappers1, keyMappers2, keyMappersAll);
    }

    /**
     * 依次返回 仅在list1中，不在list2中的列表; 同时在list1,list2中的列表; 仅在list2中，不在list1中的列表
     *
     * @param list1
     * @param list2
     * @param key
     * @param <T>
     * @return
     */
    public static <T> Triple<List<T>, List<T>, List<T>> unionKeyLeftMiddleRight(List<T> list1, List<T> list2, String... key) {
        Triple<Set<KeyMapper<T>>, Set<KeyMapper<T>>, Set<KeyMapper<T>>> idMapper = Streams.leftRightAllKeyMapper(list1, list2, key);
        List<T> left = idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && !idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
        List<T> middle = idMapper.getThird().stream().filter(v -> idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());
        List<T> right = idMapper.getThird().stream().filter(v -> !idMapper.getFirst().contains(v) && idMapper.getSecond().contains(v)).map(v -> v.obj).collect(Collectors.toList());

        return new Triple<>(left, middle, right);
    }
}
